/*
 * Copyright (c) 2012 SUBSECRETARIA DEFENSORIA DEL ESPACIO PUBLICO - SDEP.
 * All Rights Reserved.
 * This software is the confidential and proprietary information of SDEP
 * Developed By CONSTULT-SOFT S.A, Development Team 2012.
 *
 */
package co.gov.medellin.sdep.sisdep.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;

import co.gov.medellin.sdep.sisdep.common.AppConstants;
import co.gov.medellin.sdep.sisdep.common.OracleHelper;
import co.gov.medellin.sdep.sisdep.common.dto.GenericComponentVO;
import co.gov.medellin.sdep.sisdep.common.dto.GenericComponentValueVO;
import co.gov.medellin.sdep.sisdep.common.enums.ModuloStatusEnum;
import co.gov.medellin.sdep.sisdep.integration.mapasmedellin.BeanDireccion;
import co.gov.medellin.sdep.sisdep.integration.mapasmedellin.GeoUbicacionClient;
import co.gov.medellin.sdep.sisdep.model.Modulo;
import co.gov.medellin.sdep.sisdep.model.ModuloDiseno;
import co.gov.medellin.sdep.sisdep.regulacion.exception.ModuloException;
import co.gov.medellin.sdep.sisdep.regulacion.exception.ModuloRuntimeException;
import co.gov.medellin.sdep.sisdep.regulacion.service.IModuloService;


/**
 * <p>
 * Clase controladora que permite realizar el proceso de gestion de Modulos.
 * Permite al usuario realizar operaciones de consulta, creacion y actualizacion de registros.
 * </p>
 * <p>
 * Copyright (c) 2012<BR>
 * Consult-Soft S.A.<BR>
 * Created on: May 01, 2012<BR>
 * 
 * @author atabares
 * </p>
 */
public class ModuloController extends BaseController implements Serializable {

	/** Generated serial version. */
	private static final long serialVersionUID = -1021822553787482228L;

	/** Mensaje usado en el mensaje de confirmacion en la actualizacion de modulos. */
	public static final String SEARCH_RETURN = " Desea regresar a la pantalla de Consulta de Modulos?";
	
	/** Bean para el manejo del formulario de busqueda Modulo */
	private Modulo moduloSearch = new Modulo();

	/** Objeto contenedor del listado de Modulo luego de una consulta. */
	private transient DataModel moduloListModel;

	/** Bean para el manejo del formulario de creacion, edicion y resultados de consulta. */
	private Modulo modulo = new Modulo();

	/** Instancia de servicio moduloService */
	private IModuloService moduloService;

	/** Identificador de Modulo seleccionado para edicion. */
	public String selectedModuloId;
	
	/** Lista con cada uno de los disenos aplicados a los modulos. */
	private List moduloDisenoList;
	
	/** Lista de valores asociados al estado de un modulo - (ModuloStatusEnum). */
	private List moduloStatusList;
	
	/** Objeto cliente para el manejo los Barrios y Comunas dados por MapasMedellin. */
	private GeoUbicacionClient geoUbicacionClient;
	
	/** instancia un objeto de direccion local, en caso que el usuario no valide direccion al menos una vez */
	private BeanDireccion direccionLocal = new BeanDireccion();
	

	/** Constructor por defecto, inicializa los elemento basicos del Controlador. */
	public ModuloController() {
		this.moduloListModel = new ListDataModel();
	}
	
	/**
	 * Obtiene el parametro moduloSearch.
	 * @see ModuloController#moduloSearch
	 *
	 * @return El parametro moduloSearch.
	 */
	public Modulo getModuloSearch() {
		return moduloSearch;
	}

	/**
	 * Asigna el parametro moduloSearch.
	 * @see ModuloController#moduloSearch
	 *
	 * @param moduloSearch valor a asignar al parametro moduloSearch.
	 */
	public void setModuloSearch(Modulo moduloSearch) {
		this.moduloSearch = moduloSearch;
	}

	/**
	 * Obtiene el parametro moduloListModel.
	 * @see ModuloController#moduloListModel
	 *
	 * @return El parametro moduloListModel.
	 */
	public DataModel getModuloListModel() {
		return moduloListModel;
	}

	/**
	 * Asigna el parametro moduloListModel.
	 * @see ModuloController#moduloListModel
	 *
	 * @param moduloListModel valor a asignar al parametro moduloListModel.
	 */
	public void setModuloListModel(DataModel moduloListModel) {
		this.moduloListModel = moduloListModel;
	}

	/**
	 * Obtiene el parametro modulo.
	 * @see ModuloController#modulo
	 *
	 * @return El parametro modulo.
	 */
	public Modulo getModulo() {
		return modulo;
	}

	/**
	 * Asigna el parametro modulo.
	 * @see ModuloController#modulo
	 *
	 * @param modulo valor a asignar al parametro modulo.
	 */
	public void setModulo(Modulo modulo) {
		this.modulo = modulo;
	}

	/**
	 * Obtiene el parametro moduloService.
	 * @see ModuloController#moduloService
	 *
	 * @return El parametro moduloService.
	 */
	public IModuloService getModuloService() {
		return moduloService;
	}

	/**
	 * Asigna el parametro moduloService.
	 * @see ModuloController#moduloService
	 *
	 * @param moduloService valor a asignar al parametro moduloService.
	 */
	public void setModuloService(IModuloService moduloService) {
		this.moduloService = moduloService;
	}

	/**
	 * Obtiene el parametro selectedModuloId.
	 * @see ModuloController#selectedModuloId
	 *
	 * @return El parametro selectedModuloId.
	 */
	public String getSelectedModuloId() {
		return selectedModuloId;
	}

	/**
	 * Asigna el parametro selectedModuloId.
	 * @see ModuloController#selectedModuloId
	 *
	 * @param selectedModuloId valor a asignar al parametro selectedModuloId.
	 */
	public void setSelectedModuloId(String selectedModuloId) {
		this.selectedModuloId = selectedModuloId;
	}
	
	/**
	* Obtiene el parametro moduloDisenoList.
	* @see ModuloController#moduloDisenoList
	*
	* @return El parametro moduloDisenoList.
	*/
	public List getModuloDisenoList() {
		if (moduloDisenoList == null) {
			moduloDisenoList = new ArrayList();
			
			try {
				GenericComponentVO genericComponentVO = getModuloService().getModuloDisenoList();
				Iterator iter = genericComponentVO.getComponentValueList().iterator();
				
				while (iter.hasNext()) {
					GenericComponentValueVO genericComponentValueVO = (GenericComponentValueVO) iter.next();
					
					moduloDisenoList.add(new SelectItem(genericComponentValueVO.getComponentValueId(), 
							genericComponentValueVO.getComponentValueName()));
				}
			} catch (Exception e) {
				e.printStackTrace(System.err);

				((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
						.setErrorMessage(AppConstants.DEFAULT_ERROR + e.getMessage(), null, null);
			}
		}
		
		return moduloDisenoList;
	}

	/**
	* Asigna el parametro moduloDisenoList.
	* @see ModuloController#moduloDisenoList
	*
	* @param moduloDisenoList valor a asignar al parametro moduloDisenoList.
	*/
	public void setModuloDisenoList(List moduloDisenoList) {
		this.moduloDisenoList = moduloDisenoList;
	}
	

	/**
	* Obtiene el parametro moduloStatusList.
	* @see ModuloController#moduloStatusList
	* @return El parametro moduloStatusList.
	*/
	public List getModuloStatusList() {
		if (moduloStatusList == null) {
			moduloStatusList = new ArrayList();
			
			try {
				Iterator iter = ModuloStatusEnum.VALUES.iterator();
				
				while (iter.hasNext()) {
					ModuloStatusEnum moduloStatusEnum = (ModuloStatusEnum) iter.next();
					
					moduloStatusList.add(new SelectItem(moduloStatusEnum.toString(), moduloStatusEnum.toString()));
				}
			} catch (Exception e) {
				e.printStackTrace(System.err);

				((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
						.setErrorMessage(AppConstants.DEFAULT_ERROR + e.getMessage(), null, null);
			}
		}
		
		return moduloStatusList;
	}

	/**
	* Asigna el parametro moduloStatusList.
	* @see ModuloController#moduloStatusList
	*
	* @param moduloStatusList valor a asignar al parametro moduloStatusList.
	*/
	public void setModuloStatusList(List moduloStatusList) {
		this.moduloStatusList = moduloStatusList;
	}
	
	/**
	 * Obtiene el parametro geoUbicacionClient.
	 * @see ModuloController#geoUbicacionClient
	 *
	 * @return El parametro geoUbicacionClient.
	 */
	public GeoUbicacionClient getGeoUbicacionClient() {
		return geoUbicacionClient;
	}

	/**
	 * Asigna el parametro geoUbicacionClient.
	 * @see ModuloController#geoUbicacionClient
	 *
	 * @param geoUbicacionClient valor a asignar al parametro geoUbicacionClient.
	 */
	public void setGeoUbicacionClient(GeoUbicacionClient geoUbicacionClient) {
		this.geoUbicacionClient = geoUbicacionClient;
	}

	
	/**
	 * Obtiene los registros de los modulos que coinciden con los parametros de busqueda ingresados.
	 * @return La cadena que redirecciona a la pagina de resultados de busqueda de modulos.
	 */
	public String getModuloListByParameters() {
		try {
			List moduloList = new ArrayList();
			
			moduloList = getModuloService().getModuloListByCriteria(this.moduloSearch);
			
			this.moduloListModel.setWrappedData(moduloList);
		} catch (Exception e) {
			e.printStackTrace(System.err);
			
			((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
				.setErrorMessage(AppConstants.DEFAULT_ERROR + e.getMessage(), null, null);
		}
		
		if (this.moduloListModel.getWrappedData() == null 
				|| ((List) this.moduloListModel.getWrappedData()).isEmpty()) {
			
			((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
				.setAlertMessage(AppConstants.NO_RECORDS_FOUND, null, null);
		}
		
		return AppConstants.MODULO_SEARCH_VIEW;
	}
	
	/**
	 * Ajusta las propiedades de Modulos e invoca los metodos necesarios para su insercion en DB.
	 * @return La cadena que redirecciona a la pagina de creacion de modulos.
	 */
	public String create() {
		this.checkAddress();
		this.modulo.setEstado(ModuloStatusEnum.AVAILABLE.toString());
		this.modulo.setUsuarioCrea(BaseController.getLoggedUserID());
		
		String msg = null;
		
		try {
			getModuloService().insert(this.modulo);
			
			((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
				.setSuccessMessage(AppConstants.SUCCESS_CREATE, null, null);
			
			this.modulo = new Modulo();
			this.direccionLocal = new BeanDireccion();
		} catch (ModuloException e) {
			e.printStackTrace(System.err);
			
			((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
				.setErrorMessage(AppConstants.DEFAULT_ERROR + e.getEndUserMessage(), null, null);
		} catch (ModuloRuntimeException e) {
			e.printStackTrace(System.err);
			
			((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
				.setErrorMessage(AppConstants.DEFAULT_ERROR + e.getEndUserMessage(), null, null);
		}
		
		return AppConstants.MODULO_CREATE_VIEW;
	}

	public String createModulo() {
		modulo = new Modulo();
		modulo.setId(null);
		modulo.setUsuarioCrea(getLoggedUserID());
		modulo.setUsuarioModifica(getLoggedUserID());
		getModuloDisenoList();
		return AppConstants.MODULO_CREATE_VIEW;
	}
	
	/**
	 * Obtiene el modulo seleccionado desde base de datos para permitir su actualizacion.
	 * @return La cadena que redirecciona a la pagina de actualizacion de modulos.
	 */
	public String updateModulo() {
		Map params = getExternalContext().getRequestParameterMap();
		String moduloDataIndex = (String) params.get("moduloDataIndex");
		List moduloListTemp = (List) this.moduloListModel.getWrappedData();
		
		Long idModulo = ((Modulo) moduloListTemp.get(Integer.parseInt(moduloDataIndex))).getId();
		
		try {
			this.modulo = getModuloService().get(idModulo.longValue());
			getModuloDisenoList();
			this.modulo.setActualizacion(true);
		} catch (ModuloException e) {
			e.printStackTrace(System.err);
			
			((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
				.setErrorMessage(AppConstants.DEFAULT_ERROR + e.getEndUserMessage(), null, null);
		}
		
		return AppConstants.MODULO_UPDATE_VIEW;
	}
	
	/**
	 * Ajusta las propiedades de Modulos e invoca los metodos necesarios para su actualizacion en DB.
	 * @return La cadena que redirecciona a la pagina de actualizacion de modulos.
	 */
	public String update() {
		this.checkAddress();
		
		if (!this.modulo.getEstado().equals(ModuloStatusEnum.ASSIGNED.toString())) {
			this.modulo.setContrato(AppConstants.EMPTY);
			this.modulo.setEstadoFinanciero(AppConstants.EMPTY);
			this.modulo.setValorContraprestacion(new Long(0));
			this.modulo.setValorMora(new Long(0));
		}
		
		try {
			if (this.modulo.getId().longValue() != 0L) {
				getModuloService().update(this.modulo);
				
				getModuloListByParameters();
				
				((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
					.setConfirmMessage(AppConstants.SUCCESS_UPDATE + ModuloController.SEARCH_RETURN, 
						MessageModalWindowController.ACTION_NAVIGATE, AppConstants.MODULO_SEARCH_VIEW, 
							AppConstants.MODULO_UPDATE_VIEW);
			}
		} catch (ModuloException e) {
			e.printStackTrace(System.err);
			
			((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
				.setErrorMessage(AppConstants.DEFAULT_ERROR + e.getEndUserMessage(), null, null);
		} catch (ModuloRuntimeException e) {
			e.printStackTrace(System.err);
			
			((MessageModalWindowController) getBean(AppConstants.MESSAGE_CONTROLLER_BEAN))
				.setErrorMessage(AppConstants.DEFAULT_ERROR + e.getEndUserMessage(), null, null);
		}
		
		return AppConstants.MODULO_UPDATE_VIEW;
	}
	
	/**
	 * Verifica la direccion ingresada mediante el servicio web de verificacion de direcciones.
	 * @return
	 */
	public String checkAddress() {
		direccionLocal = getGeoUbicacionClient().getAddressLocalization(this.modulo.getDireccionModulo());
		
		if(null == direccionLocal) {
			direccionLocal = new BeanDireccion();
		}
		
		this.modulo.setCodigoBarrio(OracleHelper
				.isNullorEmpty(direccionLocal.getCodBarrio()) ? "N/A" : direccionLocal.getCodBarrio());
		this.modulo.setBarrio(OracleHelper
				.isNullorEmpty(direccionLocal.getValueNomBarrio()) ? "NO Disponible" : direccionLocal.getValueNomBarrio());
		this.modulo.setCodigoComuna(OracleHelper
				.isNullorEmpty(direccionLocal.getCodComuna()) ? "N/A" : direccionLocal.getCodComuna());
		this.modulo.setComuna(OracleHelper
				.isNullorEmpty(direccionLocal.getValueNomComuna()) ? "NO Disponible" : direccionLocal.getValueNomComuna());

		return AppConstants.EMPTY;
	}
	
	/**
	 * 
	 * @return
	 */
	public String cancelModulo() {
		return AppConstants.MODULO_SEARCH_VIEW;
	}
	
}
